home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Magnum One
/
Magnum One (Mid-American Digital) (Disc Manufacturing).iso
/
d12
/
du.arc
/
FSINFO.C
< prev
next >
Wrap
C/C++ Source or Header
|
1990-10-05
|
8KB
|
276 lines
/* @(#) fsinfo.c 1.2 90/09/08 14:38:57 */
/*
* Package: du - Enhanced "du" disk usage report generator.
* File: fsinfo.c - File-system information routines.
*
* The following routines are to provide the filesystem-specific support:
*
* fs_initinfo() - Initializes internal filesystem tables.
* fs_getinfo() - Get filesystem information for an entry.
* fs_linkdone() - Determines whether a file has been visited already.
* fs_numblocks() - Calculates disk usage of an entry.
*
* A linked list of (struct fsinfo) is maintained, one element per mounted
* filesystem. The "fs_initinfo()" routine initializes this list. The
* "fs_getinfo()" routine locates the element associated with the filesystem
* containing a particular file. To minimize overhead, the "fs_getinfo()"
* routine should be called only when we change directories, and the
* information on the current directory should be used for all the items
* in that directory. The "fs_linkdone()" and "fs_numblocks()" routines
* require the pointer returned by "fs_getinfo()".
*
* Sat Sep 8 14:34:56 1990 - Chip Rosenthal <chip@chinacat.Unicom.COM>
* Cleanup for distribution.
* Tue Apr 17 21:50:58 1990 - Chip Rosenthal <chip@chinacat.Unicom.COM>
* Original composition.
*
* Copyright 1990, Unicom Systems Development. All rights reserved.
* See accompanying README file for terms of distribution and use.
*/
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/statfs.h>
#include <mnttab.h>
#include "du.h"
static char SccsID[] = "@(#) fsinfo.c 1.2 90/09/08 14:38:57";
/*
* Mount table stuff.
*/
#ifndef PNMNTTAB
# define PNMNTTAB "/etc/mnttab"
#endif
#ifndef ISMNTFREE
# define ISMNTFREE(m) ( (m)->mt_dev[0] == '\0' )
#endif
#ifdef BROKE_MNTTAB /* ISC 2.0.2 botched <mnttab.h> */
# define mnttab mnttab_kludge
struct mnttab_kludge {
char mt_dev[32];
char mt_filsys[32];
char mt_stuff[12];
};
#endif
/*
* The head of a linked list list of filesystem information records.
*/
struct fsinfo *Fsinfo_list;
/*
* External procedures.
*/
extern void *memset();
/*
* fs_initinfo() - Initializes list of filesystem information.
*/
void fs_initinfo()
{
struct fsinfo *fsp, *fsp_tail;
struct mnttab mbuf;
struct stat sbuf;
struct statfs fsbuf;
FILE *fp;
int n;
Fsinfo_list = fsp_tail = NULL;
/*
* Open up the mount table.
*/
if ( (fp=fopen(PNMNTTAB,"r")) == NULL )
errmssg(ERR_ABORT,"couldn't open '%s'", PNMNTTAB);
/*
* Go through mount table and look for all mounted filesystems.
*/
while ( fread( (char *)&mbuf, sizeof(struct mnttab), 1, fp ) == 1 ) {
/*
* Ignore empty slots.
*/
if ( ISMNTFREE(&mbuf) )
continue;
/*
* Get the information on this filesystem.
*/
if ( stat(mbuf.mt_filsys,&sbuf) != 0 ) {
errmssg(ERR_WARN,"couldn't stat '%s'", mbuf.mt_filsys);
continue;
}
if ( statfs(mbuf.mt_filsys,&fsbuf,sizeof(struct statfs),0) != 0 ) {
errmssg(ERR_WARN,"couldn't statfs '%s'", mbuf.mt_filsys);
continue;
}
/*
* Allocate the filesystem information structure.
*/
fsp = (struct fsinfo *) xmalloc( sizeof(struct fsinfo) );
fsp->dev = sbuf.st_dev;
fsp->nino = fsbuf.f_files;
fsp->bsize = fsbuf.f_bsize;
fsp->nindir = fsp->bsize / sizeof(daddr_t);
fsp->next = NULL;
/*
* Create the bit vector which indicates multiply-linked inodes done.
* See fs_linkdone() for information on this bitvector.
*/
n = fsp->nino/8 + 1;
fsp->idone = (unsigned char *) xmalloc((unsigned)n);
memset(fsp->idone,0,n);
/*
* Attach the filesystem information to the end of the list.
*/
if ( Fsinfo_list == NULL )
Fsinfo_list = fsp;
else
fsp_tail->next = fsp;
fsp_tail = fsp;
}
(void) fclose(fp);
}
/*
* fs_getinfo() - Get filesystem information on a entry.
*/
struct fsinfo *fs_getinfo(fsp,sbufp)
Reg struct fsinfo *fsp; /* filesystem info on dir containing entry */
Reg struct stat *sbufp; /* stat information on the entry */
{
/*
* If we already have info on the directory containing this entry and
* this entry doesn't cross a mount point, then we can use the same info.
*/
if ( fsp != NULL && fsp->dev == sbufp->st_dev )
return fsp;
/*
* Search the linked list for this filesystem.
*/
fsp = Fsinfo_list;
while ( fsp != NULL && fsp->dev != sbufp->st_dev )
fsp = fsp->next;
return fsp;
}
/*
* fs_linkdone() - Determines whether a file has been visited already.
*
* This procedure implements the logic to avoid recounting of multiply
* linked files. Each fsinfo structure contains a bit vector for all of
* the filesystem's inodes. This procedure uses this vector to see if
* a file has been done already. The first time this procedure is called
* for a particular inode number, we return FALSE and mark it in the bit
* vector. All following times this procedure is called we return TRUE.
*/
int fs_linkdone(fsp,sbufp)
Reg struct fsinfo *fsp;
Reg struct stat *sbufp;
{
Reg unsigned char *rowp;
int mask;
/*
* Locate the bit within the vector for this inode.
*/
rowp = fsp->idone + ( sbufp->st_ino >> 3 );
mask = 1 << (sbufp->st_ino & 07);
/*
* If the bit is set then this link was already done.
*/
if ( *rowp & mask )
return TRUE;
/*
* Set the bit and indicate the link hasn't been done yet.
*/
*rowp |= mask;
return FALSE;
}
#define DIRBLKS 10 /* num direct addrs in inode */
#define CEIL_DIV(A,B) ( ((A)+(B)-1) / (B) ) /* calculate "ceiling(A/B)" */
/*
* fs_numblocks() - Calculates disk usage of an entry.
*/
long fs_numblocks(fsp,sbufp)
Reg struct fsinfo *fsp;
struct stat *sbufp;
{
Reg long n_used; /* num blocks used, incl overhead */
Reg long n_to_place; /* num data blocks to be placed */
long n_single_ind; /* scratch single indirect block cntr */
long n_double_ind; /* scratch double indirect block cntr */
/*
* Determine the number of blocks which are required to store this file.
*/
n_used = CEIL_DIV( sbufp->st_size , fsp->bsize );
n_to_place = n_used;
/*
* The first DIRBLKS blocks are directly addressed through the inode.
*/
n_to_place -= DIRBLKS;
if ( n_to_place <= 0 )
goto done;
/*
* With the single indirect block, we can get another "nindir" blocks.
*/
++n_used;
n_to_place -= fsp->nindir;
if ( n_to_place <= 0 )
goto done;
/*
* With the double indirect block, we can get another "nindir" single
* indirect blocks, for a total of another "nindir**2" data blocks.
*/
n_single_ind = CEIL_DIV( n_to_place , fsp->nindir );
if ( n_single_ind > fsp->nindir )
n_single_ind = fsp->nindir;
n_used += 1 + n_single_ind;
n_to_place -= n_single_ind * fsp->nindir ;
if ( n_to_place <= 0 )
goto done;
/*
* With the triple indirect block, we can get another "nindir" double
* indirect blocks, for another "nindir**2" single indirect blocks, for
* a total of another "nindir**3" data blocks.
*/
n_single_ind = CEIL_DIV( n_to_place , fsp->nindir );
n_double_ind = CEIL_DIV( n_single_ind , fsp->nindir );
n_used += 1 + n_double_ind + n_single_ind;
done:
/*
* Convert the usage from native blocksize to reporting blocksize.
*/
if ( Report_blksize == 0 || Report_blksize == fsp->bsize )
return n_used;
else
return CEIL_DIV( n_used*fsp->bsize , Report_blksize );
}